#!/usr/bin/env python
 
DEBUG_TARGET  = "ncurses_debug"

NATIVE_TARGET = "ncurses_debug"


import shutil

import os,sys,re

import time

from os import walk

sys.path.append("assets")

from import_from_source import *

COMMANDS_LIST = \
    [ \
    "build", "clean", "create", "c", "delete", "help", "h", \
    "list", "l", "reset", "debug", "d", "test", "tile", \
    "rebuild", "import", "size", "show", "string", "run", "r", \
    "clone", "rename", "rotate", "tools", "files", "f", \
    "commands",  "add" \
    ]



def run_command_verbosely(command_string):
    print("Going to run: " + command_string)
    os.system(command_string)

def are_you_sure():
    if sys.version_info[0] < 3:
        return raw_input("Are you sure [Y/N]? ").lower()
    else:
        return input("Are you sure [Y/N]? ").lower()


def dirs_in_path(mypath):
    dirs = []
    for (dirpath, dirnames, filenames) in walk(mypath):
        dirs.extend(dirnames)
        break
    return dirs

def files_in_path(mypath):
    files = []
    for (dirpath, dirnames, filenames) in walk(mypath):
        files.extend(filenames)
        break
    return files


def multiple_project_rebuild(params):

    mypath = params[0]
    target = params[1]
    
    if(len(params)>=3):
        reset_opts = [params[2]]
    else:
        reset_opts = []
    
    projects = []
    for (dirpath, dirnames, filenames) in walk(mypath):
        projects.extend(dirnames)
        break
            
    for project_name in projects:
        print("\n")
        print("PROJECT: " + project_name)
        print("\n")
        reset([mypath, project_name]+reset_opts)
        build([mypath, project_name, target])


def multiple_reset(mypath):
    projects = []
    for (dirpath, dirnames, filenames) in walk(mypath):
        projects.extend(dirnames)
        break
            
    for project_name in projects:
        print("PROJECT: " + project_name)
        reset([mypath, project_name])
        print("\n")


def multiple_debug_run(mypath,target,xsize,ysize,debug):
    projects = []
    for (dirpath, dirnames, filenames) in walk(mypath):
        projects.extend(dirnames)
        break
            
    for project_name in projects:
        make_command = \
            GNU_MAKE + " " + target + " XSIZE=" + xsize +  " YSIZE=" + ysize + " _DEBUG_FLAG=" + str(debug) + \
                " -f " + mypath+"/"+project_name+"/Makefile."+project_name;
                
        run_command_verbosely(make_command)


def multiple_run(mypath,target,threads,optimization):
    projects = []
    for (dirpath, dirnames, filenames) in walk(mypath):
        projects.extend(dirnames)
        break
            
    for project_name in projects:
        make_command = \
            GNU_MAKE + " " + target + \
                " ZSDCC_MAKEFILE_THREADS_OPTS=\'-j " + threads + "'" \
                " ZSDCC_MAKEFILE_COMPILATION_OPTS=" + optimization + \
                " -f " + mypath+"/"+project_name+"/Makefile."+project_name;

        run_command_verbosely(make_command)


def only_upper_and_digits(s):
    return "".join(c for c in s if c.isupper() or c in ["0","1","2","3","4","5","6","7","8","9"])


def only_upper_digits_and_space(s):
    return "".join(c for c in s if c.isupper() or c in [" ", "0","1","2","3","4","5","6","7","8","9"])


def no_space(s):
    return "".join(c for c in s if c!=" ")


def project_category(game_dir):
    if(game_dir in example_projects):
        return "example"
    elif game_dir in game_projects:
        return "game" 
    else:
        return "project" 
    

# Convert a string into a sequence of macros that can be used in the code (only necessary for small letters)
def string(params):
    string = params[1]
    m = re.search('[a-zA-Z0-9 ]*',string)
    string = m.group(0)
    
    string = string.replace(" ", "@")
    converted_string = ""
    
    for ch in string:
        converted_string+= "_XL_"+ch+" "
    
    converted_string = converted_string.replace("_XL_@", "_XL_SPACE")
    
    for i in range(9):
        converted_string = converted_string.replace("_XL_"+str(i),'"'+str(i)+'"')
    
    print(converted_string)


# Run a project natively (terminal with ncurses) with a given XSize and YSize
def size(params,debug):

    if len(params)<2:
        game_dir = "helloworld"
    else:
        game_dir = params[1]

    project_type = project_category(game_dir)

    parent_dir = project_type + "s"

    xsize = params[2]
    ysize = params[3]

    target = NATIVE_TARGET

    print("Project name       : " + game_dir)
    print("Project type       : " + project_type)
    print("XSize: " + xsize)
    print("YSize: " + ysize)

    parent_and_game_dir = parent_dir + "/" + game_dir

    if(game_dir not in ["games", "examples", "projects", "all"]):
        if not os.path.exists(parent_and_game_dir):
            print("Project not found!")
            exit();

        make_command = \
            GNU_MAKE + " " + target + " XSIZE=" + xsize +  " YSIZE=" + ysize + " _DEBUG_FLAG=" + str(debug) +  \
                " -f " + parent_dir+"/"+game_dir+"/Makefile."+game_dir;

        run_command_verbosely(make_command)
    else:
        if game_dir in["games","examples","projects"]:
            multiple_debug_run(game_dir,target,xsize,ysize,debug)
        elif game_dir in["new"]:
            multiple_debug_run("projects",target,xsize,ysize,debug)
        elif game_dir in["builtin","built-in"]:
            multiple_debug_run("games",target,xsize,ysize,debug)
            multiple_debug_run("examples",target,xsize,ysize,debug)
        elif game_dir=="all":
            multiple_debug_run("games",target,xsize,ysize,debug)
            multiple_debug_run("examples",target,xsize,ysize,debug)
            multiple_debug_run("projects",target,xsize,ysize,debug)
        else:
            exit()


# Rebuild a project, i.e., also rebuilds assets
def rebuild(params):
    game_dir = params[1]

    if game_dir=="new":
        game_dir = "projects"

    # project_groups = 

    if game_dir in ["games","examples","projects"]:
        # print([game_dir]+params[2:])
        multiple_project_rebuild([game_dir]+params[2:]) #, target, reset_opts)
        exit()
    elif game_dir in ["builtin","built-in"]:
        multiple_project_rebuild(["games"]+params[2:])
        multiple_project_rebuild(["examples"]+params[2:])
        exit()
    elif game_dir=="all":
        multiple_project_rebuild(["games"]+params[2:])
        multiple_project_rebuild(["examples"]+params[2:])
        multiple_project_rebuild(["projects"]+params[2:])
        exit()
    
    reset(params)
    if(params[len(params)-1]=="-y"):
        build(params[:-1])
    else:
        build(params)


def convert_makefile(dir,old_type,old_name,new_name):

    dest_path = "projects/"+dir
    source_game_dir = old_name
    target_game_dir = new_name
    source_parent_dir = old_type
    target_parent_dir = "projects"
    
    print("- dir: " + dir)
    print("- old_type: " + old_type)
    print("- old_name: " + old_name)
    print("- new_game: " + new_name)
    
    fin = open("./"+dest_path+"/Makefile."+source_game_dir, "rt")
    data = fin.read()
    data = data.replace('CROSS-' + source_game_dir.upper(),'CROSS-'+target_game_dir.upper())
    data = data.replace('GAME_NAME := ' + source_game_dir, 'GAME_NAME := '+target_game_dir)
    data = data.replace('PARENT_DIR = ' + source_parent_dir + "s", 'PARENT_DIR = ' + target_parent_dir)
    fin.close()
    fin = open("./"+dest_path+"/Makefile."+target_game_dir, "wt")
    fin.write(data)
    fin.close()
    
    os.remove("./"+dest_path+"/Makefile."+source_game_dir)


# Rename a project
def rename(params):
    if len(params)<2:
        source_game_dir = "helloworld"
    else:
        source_game_dir = params[1]
        
    if len(params)<3:
        print("ERROR: You need to provide more paramaters")
        exit()
        
    target_game_dir = params[2]
            
    source_project_type = project_category(source_game_dir)
    source_parent_dir = source_project_type + "s"
    source_parent_and_game_dir = source_parent_dir + "/" + source_game_dir

    if source_project_type != "project":
        exit()

    target_project_type = "project"
    target_parent_dir = target_project_type + "s"
    target_parent_dir_and_game_dir = target_parent_dir + "/" + target_game_dir
    
    print("DEBUG) source_project_type: " + source_project_type)
    
    convert_makefile(source_game_dir, source_project_type, source_game_dir, target_game_dir)
    
    os.rename(target_parent_dir + "/" +source_game_dir, target_parent_dir_and_game_dir)


# Clone a project to create a new one
def clone(params):
    if len(params)<2:
        source_game_dir = "helloworld"
    else:
        source_game_dir = params[1]
        
    if len(params)<3:
        exit()
        
    target_game_dir = params[2]
        
        
    source_project_type = project_category(source_game_dir)
    source_parent_dir = source_project_type + "s"
    source_parent_and_game_dir = source_parent_dir + "/" + source_game_dir

    target_project_type = "project"
    target_parent_dir = target_project_type + "s"
    target_parent_dir_and_game_dir = target_parent_dir + "/" + target_game_dir

    print("Source project name    : " + source_game_dir)
    print("Source Project type    : " + source_project_type)
    print("Path to source project : " + source_parent_and_game_dir)
    print("")
    print("Target project name    : " + target_game_dir)
    print("target Project type    : " + target_project_type)
    print("Path to target project : " + target_parent_dir_and_game_dir)

    # if not os.path.exists(target_parent_dir_and_game_dir):
        # print("Creating project dir...")
        # os.makedirs(target_parent_dir_and_game_dir)

    source_path = source_parent_and_game_dir
    print("source_path: " + source_path)
    dest_path = target_parent_dir_and_game_dir
    print("dest_path: " + dest_path)

    if not os.path.exists(dest_path+"/tiles"):
        print("Copying tiles...")
        shutil.copytree(source_path, dest_path)

    if not os.path.exists(dest_path+"/generated_assets"):
        print("Create empty generated_assets directory...")
        os.makedirs(dest_path+"/generated_assets")

    convert_makefile(target_game_dir, source_project_type, source_game_dir, target_game_dir)


# Generate tools from source code
def tools():
    make_command = \
        GNU_MAKE + " tools"
    run_command_verbosely(make_command)
        

# Build a project (for a target or multiple targets)
def build(params):
    if len(params)<2:
        game_dir = "helloworld"
    else:
        game_dir = params[1]

    if len(params)>=1 and game_dir=="tools":
        tools()
        exit()

    project_type = project_category(game_dir)
    parent_dir = project_type + "s"

    if len(params)<3:
        target = "ncurses"
    else:
        target = params[2]

    if len(params)<4:
        threads = "8"
    else:
        threads = params[3]


    if len(params)>=5 and params[4]=="on":
        optimization = "--max-allocs-per-node200000"
    else:
        optimization = ""

    if len(params)>=6:
        compiler_opts = params[5]
    else:
        compiler_opts = ""

    print("Project name       : " + game_dir)
    print("Project type       : " + project_type)
    print("Number of threads  : " + threads)
    print("Extra optimization : " + optimization)
    print("Compiler's options : " + compiler_opts)


    parent_and_game_dir = parent_dir + "/" + game_dir

    if(game_dir not in ["games", "examples", "projects", "all"]):
        if not os.path.exists(parent_and_game_dir):
            print("Project not found!")
            exit();

        make_command = \
            GNU_MAKE + " " + target + \
                " ZSDCC_MAKEFILE_THREADS_OPTS=\'-j " + threads + "'" \
                " ZSDCC_MAKEFILE_COMPILATION_OPTS=" + optimization + \
                compiler_opts +                                      \
                " -f " + parent_dir+"/"+game_dir+"/Makefile."+game_dir;

        run_command_verbosely(make_command)
        
    else:
        if game_dir in ["games","examples","projects"]:
            multiple_run(game_dir,target,threads,optimization)
        elif game_dir=="new":
            multiple_run("projects",target,threads,optimization)
        elif game_dir in ["builtin","built-in"]:
            multiple_run("games",target,threads,optimization)
            multiple_run("examples",target,threads,optimization)
        elif game_dir=="all":
            multiple_run("games",target,threads,optimization)
            multiple_run("examples",target,threads,optimization)
            multiple_run("projects",target,threads,optimization)
        else:
            exit()     


# Create a new project 
def create(params):
    if len(params)<2:
        game_dir = "helloworld"
    else:
        game_dir = params[1]
        game_dir_capital = game_dir.upper()        
        game_dir_capital_without_special_chars = only_upper_digits_and_space(game_dir.upper().replace("-"," ").replace("_"," "))
        
        game_dir = no_space(game_dir)
        
        if(game_dir in example_projects or game_dir in builtin_games or game_dir in COMMANDS_LIST):
            print("invalid name!")
            exit()

    if len(params)<3:
        project_type = "helloworld"
    else:
        if params[2]=="game" or params[2]=="arcade":
            project_type = "arcade_game"
        elif params[2]=="text":
            project_type = "text_game"
        else: 
            if params[2] in ["apis","show_apis","example","show"]:
                project_type = "demo"
            else:
                project_type = "helloworld"

    parent_dir = "projects" 

    print("New project name: " + game_dir)
    print("Project type: " + project_type)

    parent_and_game_dir = parent_dir + "/" + game_dir

    if not os.path.exists(parent_and_game_dir):
        print("Creating project dir...")
        os.makedirs(parent_and_game_dir)

    source_path = "./template_projects/"+project_type+"_code.template"
    print("source_path: " + source_path)
    dest_path = parent_and_game_dir
    print("dest_path: " + dest_path)

    if not os.path.exists(dest_path+"/tiles"):
        print("Copying tiles...")
        shutil.copytree(source_path+"/tiles", dest_path+"/tiles")

    if not os.path.exists(dest_path+"/generated_assets"):
        print("Create empty generated_assets directory...")
        os.makedirs(dest_path+"/generated_assets")

    file_names = ["main.c"]

    for file_name in file_names:
        print("Copying file_name: " + file_name)
        shutil.copy(source_path+"/"+file_name, dest_path)

    # Replace _GAME_NAME_CAPITAL with the capitalized game name without special characters
    fin = open("./"+dest_path+"/main.c", "rt")
    data = fin.read()
    data = data.replace('_GAME_NAME_CAPITAL',game_dir_capital_without_special_chars)
    fin.close()
    fin = open("./"+dest_path+"/main.c", "wt")
    #overrite the input file with the resulting data
    fin.write(data)
    
    templated_makefile_path = "./template_projects"

    shutil.copy(templated_makefile_path+"/"+"Makefile_game.template", "./"+dest_path+"/Makefile."+game_dir)

    #read input file
    fin = open("./"+dest_path+"/Makefile."+game_dir, "rt")
    #read file contents to string
    data = fin.read()
    #replace all occurrences of the required string
    data = data.replace('_GAME_NAME_CAPITAL',game_dir_capital)
    data = data.replace('_GAME_NAME_', game_dir)
    data = data.replace('_PARENT_DIR_', parent_dir)
    #close the input file
    fin.close()
    #open the file in write mode
    fin = open("./"+dest_path+"/Makefile."+game_dir, "wt")
    #overrite the input file with the resulting data
    fin.write(data)
    #close the file
    fin.close()


# Delete temporary project files If a project is specified, it also deletes generated assets.
def reset(params):
    game_dir = params[1]
    par_len = len(params)

    if game_dir in ["games","examples","projects"]:
        multiple_project_reset(game_dir)
        exit()
    elif game_dir=="new":
        multiple_project_reset("projects")
        exit()
    elif game_dir in ["builtin","built-in"]:
        multiple_project_reset("games")
        multiple_project_reset("examples")
        exit()
    elif game_dir=="all":
        multiple_project_reset("games")
        multiple_project_reset("examples")
        multiple_project_reset("projects") 
        exit()

    elif (len(params)==2) and (params[par_len-1]=='-y'): #(params[1]=='-y'):
        make_command = GNU_MAKE + " clean_generic_no_built_in -f makefiles.common/auxiliary/Makefile_common"

        print("Delete all non-project-specific temporary files")

        run_command_verbosely(make_command)
        exit();
        
    elif len(params)<2:
        make_command = GNU_MAKE + " clean_generic_no_built_in -f makefiles.common/auxiliary/Makefile_common"

        print("Delete all non-project-specific temporary files")
        if(are_you_sure()=="y"):
            run_command_verbosely(make_command)
            exit();
        else:
            exit();
    else:
        game_dir = params[1]

    project_type = project_category(game_dir)

    parent_dir = project_type + "s"

    if (len(params)>2) and (params[par_len-1]=='-y'): #(params[2]=="-y"):
        interactive = False
    else:
        interactive = True

    print("Project name: " + game_dir)

    parent_and_game_dir = parent_dir + "/" + game_dir

    if not os.path.exists(parent_and_game_dir):
        print("Project not found!")
        exit();

    print("Delete all temporary files including generated assets for '"+game_dir+"'")

    if (not interactive) or (are_you_sure()=="y"):
        make_command = GNU_MAKE + " clean_no_built_in -f " + parent_dir+"/"+game_dir+"/Makefile."+game_dir;

        run_command_verbosely(make_command)


# Clean project data
def clean(params):

    if(len(params)>=2) and params[1]=="tools":
        make_command = GNU_MAKE + " clean_tools"

        run_command_verbosely(make_command)
        exit()
        
    if len(params)<2:
        make_command = GNU_MAKE + " clean_generic -f makefiles.common/auxiliary/Makefile_common"

        print("Delete all built binaries and non-project=specific temporary files")
        if(are_you_sure()=="y"):
            run_command_verbosely(make_command)
            exit();
        else:
            exit();
    elif (len(params)==2) and (params[1]=='-y'):
        make_command = GNU_MAKE + " clean_generic -f makefiles.common/auxiliary/Makefile_common"

        print("Delete all built binaries and non-project-specific temporary files")

        run_command_verbosely(make_command)
        exit();
    else:
        game_dir = params[1]

    project_type = project_category(game_dir)

    parent_dir = project_type + "s"

    if (len(params)>2) and (params[2]=="-y"):
        interactive = False
    else:
        interactive = True

    print("Project name: " + game_dir)

    parent_and_game_dir = parent_dir + "/" + game_dir

    if not os.path.exists(parent_and_game_dir):
        print("Project not found!")
        exit();

    print("Delete all built binaries and temporary files (also specific to '"+game_dir+"', e.g., generated assets)")

    if (not interactive) or (are_you_sure()=="y"):
        make_command = GNU_MAKE + " clean -f " + parent_dir+"/"+game_dir+"/Makefile."+game_dir;

        run_command_verbosely(make_command)


# Delete project
def delete(params):
    if(len(params)>=2) and params[1]=="tools":
        make_command = GNU_MAKE + " clean_tools"

        run_command_verbosely(make_command)
        exit()

    if len(params)<2:
        game_dir="helloworld"
    else:
        candidate_name = params[1]
        if(candidate_name in example_projects or candidate_name in builtin_games or candidate_name in COMMANDS_LIST):
            print("invalid name!")
            exit()
        else:
            game_dir = candidate_name

    if (len(params)>2) and (params[2]=="-y"):
        interactive = False
    else:
        interactive = True

    print("Interactive: " + str(interactive))
    parent_dir = "projects"

    print("Project name: " + game_dir)

    parent_and_game_dir = parent_dir + "/" + game_dir
    print("Remove the project '"+game_dir+"' with all its files (source, graphics assets, makefile)")        
    if (not interactive) or (are_you_sure()=="y"):
        if os.path.exists(parent_and_game_dir):
            print("Deleting directory " + parent_and_game_dir)
            shutil.rmtree(parent_and_game_dir)

        makefile_name = "Makefile."+game_dir
        if os.path.exists(makefile_name):
            print("Deleting..." + makefile_name)
            os.remove(makefile_name)
        print("'" + game_dir + "' deleted")
    else:
        exit()


# Self-test xl and native build
def test(params):
    if(len(params)<2) or params[1]=="self":
        original_projects = list(["list"])

        create(["create", "_test_project"])
        projects_after_create = list(["list"])
        if("_test_project" not in projects_after_create):
            print("\nERROR: project not created") 

        build(["build", "_test_project"])

        delete(["delete","_test_project","-y"])
        projects_after_delete = list(["list"])
        if("_test_project" in projects_after_delete):
            print("\nERROR: project not deleted")
    elif params[1]=="compile":
        make_command = GNU_MAKE + " test"
        os.system(make_command)        
    elif params[1]=="z88dk_quick":
        make_command = GNU_MAKE + " z88dk_quick_test"
        os.system(make_command)     


# List all projects    
def list(params):

    if(len(params)<2):
        project_dirs = ["examples", "games", "projects"]
    elif(params[1]=="all"):
        project_dirs = ["examples", "games", "projects"]
    elif params[1] in ["games", "examples", "projects"]:
        project_dirs = [params[1]]
    elif params[1] in ["new"]:
        project_dirs = ["projects"]
    elif params[1] in ["built-in", "builtin"]:
        project_dirs = ["games", "examples"]
    else:
        exit()

    projects = []

    print("Searching folders")
    for mypath in project_dirs:
        print(mypath)

    print("")

    for mypath in project_dirs:
        for (dirpath, dirnames, filenames) in walk(mypath):
            projects.extend(dirnames)
            break
    
    print("Found: " + str(len(projects)))

    print("")

    for project in projects:
        print(project)

    return projects



def help_help():
    print("Possible values for <command>:")
    print(' '.join(str(cmd) for cmd in COMMANDS_LIST))
    print("")
    print("Use xl help <command> for <command>-specific help")
    print("\nExample:")
    print("\nxl help create              \n  It displays the help page for the 'create' command")


def run_native(params):
    command_prefix = "../build/X" + params[1] + "_ncurses"

    if len(params)>=4:
        xsize = params[2]
        ysize = params[3]
        command_string = command_prefix + "_" + xsize + "X" + ysize + "." + NATIVE_EXTENSION
    else:
        command_string = command_prefix + "." + NATIVE_EXTENSION
    run_command_verbosely(command_string)

# Run a project by using an emulator if necessary. Only few emulators are supported.
def run(params):
    
    if len(params)==2:
        run_native(params)
    
    if len(params)>=3:
        target = params[2]
        if target=="vic20":
            target = "vic20_exp_8k"
        if target=="ncurses":
            run_native(params[0:2]+params[3:])

        elif target in ["c64","vic20_exp_8k","vic20_exp_16k","plus4","c128","xpet","cbm-ii"]:
            extension = "prg"
            if target=="c64":
                emulator = "x64"
            elif target.startswith("vic20"):
                emulator = "xvic -memory 24k"
            elif target=="plus4":
                emulator = "xplus4"
            elif target=="c128":
                emulator = "x128"
            elif target=="pet":
                emulator = "xpet"
            elif target=="cbm-ii":
                emulator = "xcbm2"
                        
            command_string = emulator + " -autostartprgmode 1  ../build/X" + params[1] + "_" + target + "." + extension
            run_command_verbosely(command_string)

        else:
            run_native(params)


# It should be able to import from 
# - Assembly files that use byte directives with either decimal and hex notation
# - Assembly files that use word directives with ONLY hex notation
# - BASIC files that use decimal, hex notation or "headless" hex notation (by guessing)
def import_from_source(params, rotate = False):
    filename = params[1]

    skip_option = params[len(params)-1]=="-skip"

    xsize = 8
    ysize = 8

    tiles = rip_tiles(filename, xsize, ysize, skip_option, rotate)

    try:
        if(len(params)>=3) and "-" not in params[2]:
            store_tiles(params[2],tiles, xsize, ysize)
    except Exception as exception:
        print("Sorry! Failed to store tiles: \n" + str(exception.args))


# Show all generated files
def files():
    make_command = "ls -ls ../build"
    os.system(make_command)   


# Import a single tile from a text file that describes its shape with characters
def tile(params):

    tile,xsize,ysize = import_tile(params[1])
    
    print(tile)
    print_shape(compute_shape(tile,xsize))
    
    if(len(params)>=3):
        store_tile(params[2], tile, xsize, ysize, params[3])


# Show all commands
def commands(params):
    for command in COMMANDS_LIST:
        if len(command)>1:
            print(command)


# Show tile shapes of a given project
def show(params):
    parent_dir = project_category(params[1])+"s"
    
    if len(params)<4:
        xsize = "8"
        ysize = "8"
    else:
        xsize = params[2]
        ysize = params[3]

    if len(params)>=5:
        index = params[4]
    else:
        index = "";
    
    if index!="":
        print_shape_from_file(parent_dir, params[1], xsize, ysize, index)
    
    else:
        for i in range(NUMBER_OF_TILES):
            print_shape_from_file(parent_dir, params[1], xsize, ysize, i)
    


def add(params):
    project = params[1]
    
    target = params[2]
    
    print("project: " + project)
    print("target: " + target)
    
    proj_cat = project_category(project)
    print("project category: " + proj_cat)
    
    if(proj_cat != "project"):
        print("You cannot modify a built-in project")
        
    new_target_path = "makefiles.common/targets/"
    
    print("path: " + new_target_path)
    
    possible_targets = files_in_path(new_target_path)
    print(possible_targets)
    
    new_Makefile = "Makefile_" + target
    
    if new_Makefile in possible_targets:
        print("target found")
    else:
        print("target not found")
        exit()
    
    full_new_target_path = new_target_path + new_Makefile
    
    print("Adding this Makefile target(s)")
    command_string = "cat " + full_new_target_path
    run_command_verbosely(command_string)
    print("\n")
    
    project_path = "projects/" +  project
    
    full_project_path = project_path + "/Makefile." + project
    
    command_string = "cat " + full_new_target_path + " >> " + full_project_path
    run_command_verbosely(command_string)


def help(params):
    if len(params)<2:
        print("\nxl <command> <[optional] parameters>")   
        print("\n(or xl <project> <[optional] parameters> as a shorthand for \n xl build <project> <[optional] parameters>)")
        print("\n<parameters>")
        help_help()
    elif params[1]=="add":
        print("\nxl add <project> <target>")
        print("")
        print("It adds support for the new target <target> into <project> by modifying its Makefile.")
        print("")
    elif params[1]=="tools":
        print("\nxl tools")
        print("\n(or xl build tools)")
        print("")
        print("It builds some post-processing tools from their source code.")
        print("")
        print("This command has to be run only once to build the tools. The tools are used by few targets to generate ready to use images.")
    elif params[1]=="rename":
        print("\nxl rename <old project name> <new project name>")   
        print("It renames an existing user-defined project <old project name> to <new project name>.")
        print("")
        print("Remark: No matter the type of source project, the target project will be in the 'src/projects' directory")
        print("")
        print("Example:")
        print("If you have previously created a new project 'foo'")
        print("(e.g., by cloning it with 'xl clone bomber foo'),")
        print("then you can rename it to 'bar' with")
        print("xl rename foo bar")
    elif params[1]=="clone":
        print("\nxl clone <source project> <target project>")   
        print("It clones an existing project of any type to create a new user-defined project.")
        print("")
        print("Remark: No matter the type of source project, the target project will be in the 'src/projects' directory")
        print("")
        print("Example:")
        print("If you want to clone the built-in game Cross Horde you can just do:")
        print("xl clone horde foo")
        print("")
        print("If you have previously created a user-defined project 'foo',")
        print("you can further clone it with:")
        print("xl clone foo bar")
    elif params[1]=="show":
        print("xl show <project> <[optional] XTileSize> <[optional] YTileSize> <[optional] TileIndex>.")
        print("It displays the shape of graphics tiles of a given project.")
        print("")
        print("<project>")
        print("Use this mandatory parameter to specify the project whose tiles you want to display")
        print("")
        print("<XTileSize> <YTileSize>")
        print("These optional parameters specify the size of the tiles we want to see")
        print("")
        print("<TileIndex>")
        print("This optional parameter specifies which tile we want to display.")
        print("When no index is specified, then all tiles of the given shape are displayed.")
        print("")
        print("Example:")
        print("xl show chase 8 8 5")
        print("Decoding file tile: ./games/chase/tiles/8x8/tile5.txt")
        print("")
        print("..####..")
        print(".#....#.")
        print("#.#..#.#")
        print("#..##..#")
        print("#..##..#")
        print("#.#..#.#")
        print(".#....#.")
        print("..####..")
        
    elif params[1]=="size":
        print("xl size <project> <XSize> <YSize>")
        print("It builds <project> for the native host with screen size provided by <XSize> and <YSize>.")
        print("The built binaries will be in the 'build' directory.")

        print("\n<project>")
        print("<project> can also be 'games'/'examples'/'projects'/'all' to build multiple projects.")   
        
        print("\nxl size bomber 20 20       \n  It builds Cross Bomber for the native host with screen size 20x20.")
        print("\nxl reize examples 16 12     \n  It builds all examples for the native host with screen size 16x12.")

    elif params[1]=="run" or params[1]=="r":
        print("xl run <project> <[optional] xsize> <[optional] ysize>")
        print("xl run <project> <[optional] target>")
        print("If no target is specified, it runs the previously compiled native version of <project>.")
        print("If integer parameters <xsize> and <ysize> are provided, then it runs the version of those sizes.")
        print("")
        print("<project>")
        print("This parameter is the name of the project that we want to run.")
        print("")
        print("<xsize> <ysize>")
        print("These parameters are the size of the native version that we want to run.")
        print("")
        print("<target>")
        print("This parameter is the target for which we want to run <project>.")
        print("This parameter only works for a restricted set of targets and it requires an emulator.")
        print("")
        print("Examples:")
        print("xl run snake")
        print("It runs the previously built (e.g., with 'xl build snake') native version of Cross Snake.")
        print("")  
        print("xl run snake 16 16")
        print("It runs the previously built with size 16X16 (with 'xl size snake 16 16') native version of Cross Snake.")

    elif params[1]=="string":
        print("xl string <string>")
        print("It converts a string litteral into a concatenation of")
        print('_XL_A,..., _XL_Z, _XL_a, ..., _XL_z, _XL_SPACE, "0", ..., "9"')
        print("<string>")
        print("This parameter is the string to convert. It has to match the regular expression '[A-Za-z0-9 ]*'.")
        print("")
        print("Example:")
        print('xl string "1 Hello World 2"')
        print('"1" _XL_SPACE _XL_H _XL_e _XL_l _XL_l _XL_o _XL_SPACE _XL_W _XL_o _XL_r _XL_l _XL_d _XL_SPACE "2"')
    elif params[1]=="rebuild":
        print("xl rebuild <project> <[optional] target>")
        print("It rebuilds <project>.")
        print("It is equivalent to 'xl reset' followed by 'xl build <project> <target>'")
        print("Use 'xl help reset' and 'xl help build' for more information")
    elif params[1]=="import":
        print("xl import <source_file> <[optional] project>")
        print("")
        print("<source_file>")
        print("It is an Assembly or BASIC file (e.g., an Assembly file exported from CharPad or VChar64).")
        print("For example in CharPad you can export the tile data with:")
        print("File->Import/Export->Text/Asm->Export All or File->Import/Export->Text/Asm->Export All")
        print("")
        print("<project>")
        print("If a project name is passed then the tiles are imported into <project> as 8x8 tiles")
        print("")
        print("Example:")
        print("If you create a new project 'myname' with")
        print("xl create myname")
        print("You can import a tile into it from an Assembly file with something like this:")
        print("xl import ./assets/examples/tile_sets/asm/tile_8x6_shapeA.txt myname")
    elif params[1]=="rotate":
        print("xl rotate <source_file> <[optional] project>")
        print("")
        print("It works similarly to 'xl import <source> <[optional] project>' but rotates the result.")
        print("")
        print("<source_file>")
        print("It is an Assembly or BASIC file (e.g., an Assembly file exported from CharPad or VChar64).")
        print("For example in CharPad you can export the tile data with:")
        print("File->Import/Export->Text/Asm->Export All or File->Import/Export->Text/Asm->Export All")
        print("")
        print("<project>")
        print("If a project name is passed then the tiles are imported into <project> as 8x8 tiles")
        print("")
        print("Example:")
        print("If you create a new project 'myname' with")
        print("xl create myname")
        print("You can import a tile into it from an Assembly file with something like this:")
        print("xl rotate ./assets/examples/tile_sets/asm/tile_8x6_shapeA.txt myname")
    elif params[1]=="tile":
        print("xl tile <shape_file> <[optional] project> <[optional] tile_index>")
        print("It converts the file <shape_file> into a line that can be used as an asset file.")
        print("")  
        print("<shape_file>")
        print("The file <shape_file> describes with '#' and '.' the shape of a tile.")
        print("")
        print("<project>")
        print("This optional parameter specifies the project whose tile we want to modify")
        print("")
        print("<tile_index>")
        print("This parameter is the index of the tile we want to modify")
        
        print("\nPress ENTER to continue...")
        time.sleep(1)

        if sys.version_info[0] < 3:
            raw_input()
        else:
            input()
            
        print("\nExample in 'src/examples/tiles/tile_shape0.txt':")
        print("...##...")
        print("..#..#..")
        print("...##...")
        print(".##..##.")
        print("#.####.#")
        print("# ####.#")
        print("..#..#..")
        print("..#..#..")
        print("")
        print("xl tile ./assets/examples/single_tiles/tile_shape0.txt")
        print("produces: ")
        print("24,36,24,102,189,189,36,36")
        print("")
        print("To be copied in 'tile_<index>.txt' in '<project>/tiles/8x8' to modify the shape.")
        print("Remark: run 'xl reset <project>' before rebuilding <project> with modified tiles.")
        
    elif params[1]=="test":
        print("xl test <[optional] params>")
        print("It runs some operations to test 'xl'.")
        print("")
        print("<params>")
        print("If 'self' or nothing is passed to <params>, then it self-tests by performing a sequence of 'xl' commands.")
        print("If 'compile' is passed to <params>, then it compiles a test program for some targets with different compilers.")
        print("If 'z88dk_quick' is passed to <params>, then it compiles a test program using both Z88DK compilers.")
    elif params[1]=="debug" or params[1]=="d":
        print("xl debug <project> <XSize> <YSize>")
        print("It builds <project> for the native host in debug mode with screen size provided by <XSize> and <YSize>.")
        print("The built binaries will be in the 'build' directory.")

        print("\n<project>")
        print("<project> can also be 'games'/'examples'/'projects'/'all' to build multiple projects.")   
        
        print("\nxl debug bomber 20 20       \n  It builds Cross Bomber for the native host in debug mode with screen size 20x20.")
        print("\nxl debug examples 16 12     \n  It builds all examples for the native host in debug mode with screen size 16x12.")

        
    elif params[1]=="files":
        print("xl files")
        print("It shows the built binary files (the conent of the `build` directory).")
        print("Remark: 'xl files' can be shorten with `xl f`.")
    elif params[1]=="build":
        print("xl build <project> <[optional] target>")
        print("It builds <project> for <target>.")
        print("Remark: The 'build' command can be omitted.")
        print("The built binaries will be in the 'build' directory.")

        print("\n<project>")
        print("<project> can also be 'games'/'examples'/'projects'/'all' to build multiple projects")   
        
        print("\n<target>")
        print("If no <target> is passed, then the native target (terminal console) is considered.")
        print("\nIf '<dev-kit>_targets' is passed as <target> (e.g., 'cc65_targets'), \nthen the given project/s is/are built for all targets that use <dev-kit> to be compiled.")
        print("Possible dev-kits are: 'cc65', 'z88dk', 'cmoc', 'lcc1802'.") 
        print("\n[NOT recommended] If 'all' is passed as <target>, then the given project/s is/are built for all targets (it may take very long and it requires all supported compilers.") 
        
        print("\nPress ENTER to continue...")
        time.sleep(1)

        if sys.version_info[0] < 3:
            raw_input()
        else:
            input()
        
        print("\nExamples:")
        print("\nxl build bomber vic20       \n  It builds Cross Bomber for the Commodore Vic 20 using CC65.")
        print("\nxl snake                    \n  It builds Cross Snake for the native target (terminal console).")
        print("\nxl chase cc65_targets       \n  It builds Cross Chase for all targets that use CC65 to be built.")
        print("\nxl games cpc                \n  It builds all games for the Amstrad CPC using Z88DK.")
        print("\nxl examples c64             \n  It builds all examples for the Commodore 64 using CC65.")
        print("\nxl horde all                \n  It builds Cross Horde for all its supported targets using all supported necessary compilers.")
        print("\nxl projects all             \n  It builds all built-in projects for all supported targets using all supported necessary compilers.")
        print("\nxl all c16                  \n  It builds all projects (games and examples and user-defined projects) for the Commodore 264 series using CC65.")
    elif params[1]=="create" or params[1]=="c":
        print("xl create <project> <[optional] type>")
        print("It creates <project>.")
        
        print("\n<type>")
        print("If no <type> is passed, then the initial code will just display 'hello world'")
        print("If 'game' is passed as <type>, then the project is build with some initial template game code.")
        print("If 'apis' is passed as <type>, then the project is build with some code that shows how to use all APIs.")
        
        print("\nExamples:");
        print("\nxl create foo               \n  It builds a new project 'foo' with some initial code that display 'hello world' on the screen.")
        print("\nxl create bar game          \n  It builds a new project 'bar' with some initial game code (main loop, level loop, etc.).")
    elif params[1]=="delete":
        print("xl delete <project> <[optiona] interactive>")
        print("It removes <project>, i.e., it deletes its folder with its content (source code, graphics assets, makefile).")
        
        print("\n<project>")
        print("<project> cannot be a built-in project.")

        print("\n<interactive>")
        print("If '-y' is passed as <interactive>, then the command won't ask for confirmation.")

        print("\nExample:")
        print("\nxl delete foo               \n  It deletes the project 'foo'.")
        print("\nxl delete foo -y            \n  Same as above but no confirmation is asked.")   
    elif params[1]=="reset":
        print("xl reset <[optional] project> <[optiona] interactive>")
        print("It deletes temporary files created during the build process.")
        print("\n<project>")
        print("If no <project> is passed, only non-project specific temporary files are deleted.") 
        print("If the <project> parameter is used, then also project-specific temporary files are deleted (and in particular generated graphics assets).")
        
        print("\n<interactive>")
        print("If '-y' is passed as <interactive>, then the command won't ask for confirmation.")
        
        print("\nExamples:")
        print("\nxl reset                    \n  It deletes non-project specific temporary files.")
        print("\nxl reset foo                \n  It deletes all temporary files (both generic and project-specific).")
        print("\nxl reset foo -y             \n  Same as above but no confirmation is asked.")
    elif params[1]=="clean": 
        print("xl clean <[optional] project> <[optiona] interactive>")
        print("It deletes both built binaries and temporary files created during the build process.")
        print("\n<project>")
        print("If no <project> is passed, only built binaries and non-project specific temporary files are deleted.") 
        print("If the <project> parameter is used, then also project-specific temporary files are deleted (e.g., generated graphics assets).")
        
        print("\n<interactive>")
        print("If '-y' is passed as <interactive>, then the command won't ask for confirmation.")
        
        print("\nExamples:")
        print("\nxl clean                    \n  It deletes all built binaries and non-project specific temporary files.")
        print("\nxl clean foo                \n  It deletes all built-in binaries and all temporary files (both generic and project-specific).")
        print("\nxl clean foo -y             \n  Same as above but no confirmation is asked.")

    elif params[1]=="list" or params[1]=="l":  
        print("xl list <[optional] params>")
        print("It lists current projects in a given category or all projects.")
        print("")
        print("<params>")
        print("If nothing is passed as <params> then all projects are built")
        print("If 'games','examples' or 'projects' is passed as <params> then only projects in the respective directory are listed")
        print("\nExamples:")
        print("xl list                       \n  It lists all projects (games, examples and new projects)")
        print("xl list projects              \n  It lists all user-defined projects") 
        
    elif params[1]=="commands":
        print("xl commands")
        print("It displays the available commands.")
        
    elif params[1]=="help" or params[1]=="h":
        print("xl help <[optional] command>")
        print("It displays help instructions.")
        
        
        print("\n<command>")
        help_help()
    else:
        print("Command not recognized")
        exit()

# ---------------------------------------------


# ---------------------------------------------
#  System               Value               
# ---------------------------------------------
#  Linux                linux or linux2 (*) 
#  Windows              win32               
#  Windows/Cygwin       cygwin              
#  Windows/MSYS2        msys                
#  Mac OS X             darwin              
#  OS/2                 os2                 
#  OS/2 EMX             os2emx              
#  RiscOS               riscos              
#  AtheOS               atheos              
#  FreeBSD 7            freebsd7            
#  FreeBSD 8            freebsd8            
#  FreeBSD N            freebsdN            
#  OpenBSD 6            openbsd6            
# ---------------------------------------------


# ---------------------------------------------
if __name__ == "__main__":
    platform = sys.platform
    
    print("----------------------------")
    print("Cross-Lib `xl` helper script")
    print("----------------------------")
    print("Platform: " + platform)
    if(platform in ["cygwin", "linux", "linux2", "darwin", "msys", "win32"]):
        GNU_MAKE="make"
    else:
        GNU_MAKE="gmake"

    if(platform in ["cygwin", "msys"]):
        NATIVE_EXTENSION="exe"
    else:
        NATIVE_EXTENSION="out"
        
    print("GNU MAKE command: " + GNU_MAKE)
    print("----------------------------")
    print("")
    builtin_games = ["chase","shoot","bomber","snake","horde"]
    game_projects = dirs_in_path("./games")
    example_projects = dirs_in_path("./examples")
    
    if len(sys.argv)<2:
        print("You need to provide a command or a project name")
        help(sys.argv[1:])
    elif sys.argv[1]=="run" or sys.argv[1]=="r":
        run(sys.argv[1:])
    elif sys.argv[1]=="add":
        add(sys.argv[1:])
    elif sys.argv[1]=="string":
        string(sys.argv[1:])
    elif sys.argv[1]=="commands":
        commands(sys.argv[1:])
    elif sys.argv[1]=="import":
        import_from_source(sys.argv[1:],False)
    elif sys.argv[1]=="rotate":
        import_from_source(sys.argv[1:],True)
    elif sys.argv[1]=="rebuild":
        rebuild(sys.argv[1:])
    elif sys.argv[1]=="rename":
        rename(sys.argv[1:])
    elif sys.argv[1]=="clone":
        clone(sys.argv[1:])
    elif sys.argv[1]=="show":
        show(sys.argv[1:])
    elif sys.argv[1]=="test":
        test(sys.argv[1:])
    elif sys.argv[1]=="tile":
        tile(sys.argv[1:])
    elif sys.argv[1]=="build":
        build(sys.argv[1:])
    elif sys.argv[1]=="files" or sys.argv[1]=="f":
        files()
    elif sys.argv[1]=="size":
        size(sys.argv[1:],0)
    elif sys.argv[1]=="debug" or sys.argv[1]=="d":
        size(sys.argv[1:],1)
    elif sys.argv[1]=="create" or sys.argv[1]=="c":
        create(sys.argv[1:])
    elif sys.argv[1]=="clean":
        clean(sys.argv[1:])
    elif sys.argv[1]=="reset":
        reset(sys.argv[1:])
    elif sys.argv[1]=="delete":
        delete(sys.argv[1:])
    elif sys.argv[1]=="list" or sys.argv[1]=="l":
        list(sys.argv[1:])
    elif sys.argv[1]=="help" or sys.argv[1]=="h":
        help(sys.argv[1:])
    elif sys.argv[1]=="tools":
        tools()
    else:
        print(sys.argv)
        build(sys.argv)
